package com.kun.auth.extractor;

import com.kun.auth.properties.IntrospectionProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * jwt 和 不透明令牌 结合使用
 * NimbusReactiveOpaqueTokenIntrospector 只会校验授权服务器中是否存在token不会校验token是否过期
 * NimbusReactiveJwtDecoder 会校验token是否过期
 *
 * @author kun.li
 */
@Component("jwtOpaqueTokenIntrospector")
public class JwtOpaqueTokenIntrospector implements ReactiveOpaqueTokenIntrospector {

    @Autowired
    private IntrospectionProperties introspectionProperties;

    @Autowired
    private ReactiveJwtDecoder reactiveJwtDecoder;



    @Override
    public Mono<OAuth2AuthenticatedPrincipal> introspect(String token) {

        // 这个实例没有作为当前类的一个实例的目的是可以动态获取到配置中心的改变值
        ReactiveOpaqueTokenIntrospector delegate = new NimbusReactiveOpaqueTokenIntrospector(introspectionProperties.getUri(), introspectionProperties.getClientId(), introspectionProperties.getClientSecret());
        // this.delegate.introspect(token)  只会校验授权服务器中是否存在token不会校验token是否过期
        // 每调用一次就会去认证中心去查询这个token是否存在
        // 如果我们想要退出系统,1. 先移除token 2. 调用注销接口
        // 如果不先移除token 就会造成token其实并没有失效,在postman调用工具中依旧可以使用
        // 因此才会采用每次都去调用一次认证中心查看token是否被消除了,后续可以改为从redis中读取,增加系统性能.
        // this.jwtDecoder.decode(token) 会对token进行解密以及校验token是否过期
        // 这里 this.delegate.introspect(token) 每次调用认证中心我们可以使用redis来优化
        return  delegate.introspect(token)
                .flatMap(principal -> {
                    System.out.println(principal.getName());
                    System.out.println(principal.getAttributes());
                    System.out.println(principal.getAuthorities());
                    return this.reactiveJwtDecoder.decode(token);
                })
                .map(jwt -> new DefaultOAuth2AuthenticatedPrincipal(jwt.getClaims(), AuthorityUtils.createAuthorityList(jwt.getClaimAsStringList("authorities"))));
    }


}